#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:taotieren


"""
    rpi.gpio 需要 root 权限，板上运行需要使用
    sudo python thermistor.py
    热敏电阻测量温度
        热敏电阻，2 个 1KΩ 电阻，330nF 电容
        Pin_18 -- 1K ---- RP_1Pin
        Pin_23 -- 1K ---- RP_2Pin
                       |
                       |
                      330nF
                       |
                       |
         GND -----------

新加入的 read_temp_c 函数
是将热敏电阻的阻值转换为摄氏温度
用 Steinhat-Hart 方程进行一些列复杂的运算，
这个方程需要知道热敏电阻的两个值：在 25℃（称为 T0 T25） 的电阻值，以及热敏电阻的一个常量，称为 Beta 或 B（β）
如果使用不同的热敏电阻的话，请在替换程序顶部的变量 B 和 R0
电容器一般只有 10% 的准确性，热敏电阻 R0 也是这样，如果想要通过热敏电阻获得精确的值，就必须调整变量 C 和 R0 的值
可以使用 1% 精度的 1K 电阻来替换 10% 精度的电阻

摄氏温度转换为华氏温度
    Tf = Tc * 9 / 5 + 32
本程序还可以在甲烷检测模块上使用，通过向甲烷传感器吹气来进行测试，当你向其吹气的时候，你将看到传感器的读数回下降。
甲烷气体传感器
    B       A
    H       H
    B       A
"""

""" 非树莓派环境下可以用 rpi.gpio_def 代替 rpi.gpio 来进行程序调试和验证 """
import RPi.GPIO as GPIO
import time, math

C = 0.36  # uF
R1 = 1000  # Ohms
B = 3800.0  # 热敏电阻常数
R0 = 1100.0  # 热敏电阻的电阻为 25℃

GPIO.setmode(GPIO.BCM)

# 引脚 a 通过固定的 1K 电阻对电容充电
# 和热敏电阻串联
# 引脚 b 通过固定的 1K 电阻对电容放电
a_pin = 18
b_pin = 23


# 将电容器放电，准备开始充满电
def discharge():
    GPIO.setup(a_pin, GPIO.IN)
    GPIO.setup(b_pin, GPIO.OUT)
    GPIO.output(b_pin, False)
    time.sleep(0.1)


# 返回 C 充电的时间（us）
# 这是 1.65V 或更高
def charge_time():
    GPIO.setup(b_pin, GPIO.IN)
    GPIO.setup(a_pin, GPIO.OUT)
    GPIO.output(a_pin, True)
    t1 = time.time()
    while not GPIO.input(b_pin):
        pass
    t2 = time.time()
    return (t2 - t1) * 1000000


# 从充电时间中获取模拟读数
def analog_read():
    discharge()
    t = charge_time()
    discharge()
    return t


# 将电容器充电所需的时间转换为电阻值
# 要减少错误，请执行 10 次并取平均值。
def read_resistance():
    n = 10
    total = 0
    for i in range(1, n):
        total = total + analog_read()
    t = total / float(n)
    T = t * 0.632 * 3.3
    r = (T / C) - R1
    return r


def read_temp_c():
    R = read_resistance()
    t0 = 273.15  # K 表示 0 摄氏度
    t25 = t0 + 25.0  # K 为 25 摄氏度
    # Steinhart-Hart 方程式 - 谷歌它
    inv_T = 1 / t25 + 1 / B * math.log(R / R0)
    T = (1 / inv_T - t0)
    return T


try:
    while True:
        print(read_temp_c())
        time.sleep(0.5)
finally:
    GPIO.cleanup()
